#include <iostream>
#include "SingletonDemo.h"
#include "FactoryDemo.h"
#include "StrategyDemo.h"
#include "PrototypeDemo.h"
#include "CompositeDemo.h"
#include "CommondDemo.h"

void testSingleton()
{
    std::cout << "\n\n\n\n---- testSingleton ---\n\n";

    tnmujoy::gdut::SingletonManager::initialize();

    SingletonDemo::instance().run();
    SingletonDemo::instancePtr()->run();

    tnmujoy::gdut::SingletonManager::release();
}

void testFactory()
{
    std::cout << "\n\n\n\n---- testFactory ---\n\n";

    std::cout << "ProductsA : " << FactoryDemoA::productsToString() << std::endl;
    ProductDemoA* productDemoA1 = FactoryDemoA::create<ProductDemoA1>();
    productDemoA1->test();
    ProductDemoA* productDemoA2 = FactoryDemoA::create<ProductDemoA2>();
    productDemoA2->test();

    std::cout << "\nProductsB : " << FactoryDemoB::productsToString() << std::endl;
    ProductDemoB* productDemoB1 = FactoryDemoB::create("ProductDemoB1");
    productDemoB1->test();
    ProductDemoB* productDemoB2 = FactoryDemoB::create("ProductDemoB2");
    productDemoB2->test();

    std::cout << "\nProductsC : " << FactoryDemoC::productsToString() << std::endl;
    ProductDemoC* productDemoC = 0;
    FactoryDemoC::setProductName("C1");
    productDemoC = FactoryDemoC::create();
    productDemoC->test();
    FactoryDemoC::setProductName("C2");
    productDemoC = FactoryDemoC::create();
    productDemoC->test();
    /* FactoryDemoC::setProductName("C3");
    if(productDemoC = FactoryDemoC::create())
    productDemoC->test();
    else
    std::cout<<FactoryDemoC::lastErrorString()<<std::endl;*/
}

void testStrategy()
{
    std::cout << "\n\n\n\n---- testStrategy ---\n\n";

    std::cout << "StrategiesA : " << StrategyDemoA::strategiesToString() << std::endl;
    StrategyDemoA demoA;
    demoA.setStrategy(new StrategyA1);
    demoA.test();
    demoA.setStrategy(new StrategyA2);
    demoA.test();

    {
        std::cout << "\nStrategiesB : " << StrategyDemoB::strategiesToString() << std::endl;
        StrategyDemoB demoB;
        demoB.useStrategy<StrategyB1>();
        demoB.test();
        demoB.useStrategy<StrategyB2>();
        demoB.test();
    }

    std::cout << "\nStrategiesC : " << StrategyDemoC::strategiesToString() << std::endl;
    StrategyDemoC demoC;
    demoC.useStrategy("C1");
    demoC.test();
    demoC.useStrategy("C2");
    demoC.test();
}

void testPrototype()
{
     std::cout << "\n\n\n\n---- testPrototype ---\n\n";

     ProtptypeDemo demoA;
     demoA.Number = 100;
     demoA.String = "String";

     ProtptypeDemo* demoB = demoA.clone();
     demoB->test();
     demoA.Number = 200;
     demoB->test();
}

void testComposite()
{
    std::cout << "\n\n\n\n---- testComposite ---\n\n";

    CompositeDemo* root = new CompositeDemo("Root");

    CompositeDemo* compositeL = new CompositeDemo("CL");
    CompositeDemo* compositeR = new CompositeDemo("CR");

    root->add(compositeL);
    root->add(compositeR);

    LeafDemo* leafCL1 = new LeafDemo("CL-1");
    LeafDemo* leafCL2 = new LeafDemo("CL-2");
    compositeL->add(leafCL1);
    compositeL->add(leafCL2);

    LeafDemo* leafCR1 = new LeafDemo("CR-1");
    LeafDemo* leafCR2 = new LeafDemo("CR-2");
    compositeR->add(leafCR1);
    compositeR->add(leafCR1);

    root->test();
    compositeL->test();
}
void testCommond()
{
    std::cout << "\n\n\n\n---- testCommond ---\n\n";

    Receiver* receiver = new Receiver();
    tnmujoy::gdut::Invoker<Receiver>* invoker = new tnmujoy::gdut::Invoker<Receiver>();
    OpenCommond* openCmd = new OpenCommond();
    openCmd->setReceiver(receiver);
    CloseCommond* closeCmd = new CloseCommond();
    closeCmd->setReceiver(receiver);

    invoker->setCommond(openCmd);
    invoker->runCommond();

    invoker->setCommond(closeCmd);
    invoker->runCommond();
}
int main()
{
    testSingleton();
    testFactory();
    testStrategy();
    testPrototype();
    testComposite();
    testCommond();
}
